#include "MODBUS485_MASTER.h"

MODBUS485_MASTER_T* MODBUS485_MASTER_t;
MODBUS485_MASTER_List_Par_t MODBUS485_MASTER_List_Par;

//************************************
// Method:    	CARD_WORK					modbus-485主站工作函数
// Programmer:  lww
// Time:		2019/2/24
// Returns:   	void
//************************************
void CARD_WORK(MODBUS485_MASTER)()
{
	Port_State_t* Port_State;
	PortThread_Par_t *PortThread_Par0, *PortThread_Par1;
	pthread_t tMODBUS485_MASTER_RW_ID0 = 0;
	pthread_t tMODBUS485_MASTER_RW_ID1 = 0;

	//< 初始化串口状态配置结构体
	Port_State = (Port_State_t*)calloc(1, sizeof(struct Port_State_t));
	Port_State->Port0_State = UNCONNECT;
	Port_State->Port1_State = UNCONNECT;
	Port_State->Port0_Fail_Count = 0;
	Port_State->Port1_Fail_Count = 0;
	
	//< 启动串口0读写线程
	PortThread_Par0 = (PortThread_Par_t *)calloc(1, sizeof(struct PortThread_Par_t));
	PortThread_Par0->Port_Chosen = PORT0;
	PortThread_Par0->Port_Name = PORT0_485;
	PortThread_Par0->pt = Port_State;
	THREAD_CREATE_FAILED(Thread_Create("tMODBUS485_MASTER_RW_ID0", &tMODBUS485_MASTER_RW_ID0, NULL, SCHED_POLICY, 89, true, tMODBUS485_MASTER_Work_Thread, CONTROL_CORE, PortThread_Par0));
	//< 启动串口1读写线程
	PortThread_Par1 = (PortThread_Par_t*)calloc(1, sizeof(struct PortThread_Par_t));
	PortThread_Par1->Port_Chosen = PORT1;
	PortThread_Par1->Port_Name = PORT1_485;
	PortThread_Par1->pt = Port_State;
	THREAD_CREATE_FAILED(Thread_Create("tMODBUS485_MASTER_RW_ID1", &tMODBUS485_MASTER_RW_ID1, NULL, SCHED_POLICY, 89, true, tMODBUS485_MASTER_Work_Thread, CONTROL_CORE, PortThread_Par1));
}

//************************************
// Method:    	tMODBUS485_MASTER_Work_Thread	MODBUS-485主站工作线程
// Programmer:  lww
// Time:		2019/2/25
// Returns:   	void *
// Parameter: 	void * arg
//************************************
void *tMODBUS485_MASTER_Work_Thread(void* arg)
{
#define MAX_LINK_FAIL_NUM	3
#define MAX_WORK_FAIL_NUM	3
#define STATE	((Port_Chosen == PORT0) ? (Port_State->Port0_State) : (Port_State->Port1_State))
#define OTHER_PORT_STATE	((Port_Chosen == PORT0) ? (Port_State->Port1_State) : (Port_State->Port0_State))
#define FAILED_COUNT	((Port_Chosen == PORT0) ? (Port_State->Port0_Fail_Count) : (Port_State->Port1_Fail_Count))
#define CARD_NUM	(Card_List[TYPE(MODBUS485_MASTER)].iCount)
#define PORT_STATE_WRITE(name)	{\
	if (Port_Chosen == PORT0)\
		Port_State->Port0_State = name;\
	if (Port_Chosen == PORT1)\
		Port_State->Port1_State = name;\
}
#define WRITE_CARD_TIMEOUT_STATE	{\
	for (i = 0; i < CARD_NUM; i++)\
	{\
		base = (NAME(MODBUS485_MASTER)*)SearchAt(((List_Base_t*)Card_List[TYPE(MODBUS485_MASTER)].ppData[0]), i);\
		base->Base.Status |= 0x08;		/*卡件超时*/\
	}\
}
#define CANCEL_CARD_TIMEOUT_STATE	{\
	for (i = 0; i < CARD_NUM; i++)\
	{\
		base = (NAME(MODBUS485_MASTER)*)SearchAt(((List_Base_t*)Card_List[TYPE(MODBUS485_MASTER)].ppData[0]), i);\
		base->Base.Status &= 0xF7;		/*卡件取消超时*/\
	}\
}
#define WRONG_DEAL	{\
	close(fd);\
	FAILED_COUNT++;\
	if (FAILED_COUNT >= MAX_LINK_FAIL_NUM)	{ FAILED_COUNT = MAX_LINK_FAIL_NUM; }\
	if ((Port_State->Port0_Fail_Count >= MAX_LINK_FAIL_NUM) && (Port_State->Port1_Fail_Count >= MAX_LINK_FAIL_NUM))	{ WRITE_CARD_TIMEOUT_STATE; }\
	PORT_STATE_WRITE(UNCONNECT);\
}

	int fd = -1;
	PortThread_Par_t PortThread_Par;
	Port_Chosen_e Port_Chosen;					//< 该线程所运行串口情况
	const char* Port_Name;						//< 串口设备名
	Port_State_t* Port_State;					//< 串口状态
	unsigned int Band_Rate;						//< 波特率
	unsigned int Data_Bits;						//< 数据位
	char Check_Bit;								//< 校验位
	char Stop_Bit;								//< 停止位
	int i;
	NAME(MODBUS485_MASTER)* base;
	char Wrong_Sum;								//< 每张卡件通讯失败次数累加值
	bool* Card_Wrong_Flag;						//< 卡件通讯错误数组指针
	char Wrong_Count = 0;						//< 通讯错误的卡件数量累加

	Card_Wrong_Flag = (bool*)calloc(CARD_NUM, sizeof(bool));

		//< duan20200610

	//< 解析传入参数
	PortThread_Par = *(PortThread_Par_t*)arg;
	Port_Chosen = PortThread_Par.Port_Chosen;
	Port_Name = PortThread_Par.Port_Name;
	Port_State = PortThread_Par.pt;

	Band_Rate = BandRate_Trans(MODBUS485_MASTER_List_Par.Band_Rate);
	Data_Bits = DataBits_Trans(MODBUS485_MASTER_List_Par.Data_Bits);
	Check_Bit = MODBUS485_MASTER_List_Par.Check_Bit;
	Stop_Bit = MODBUS485_MASTER_List_Par.Stop_Bit;

	printf("the %s Kernel_%s is %d\r\n", Port_Name, "tMODBUS485_MASTER_Work_Thread_ID", syscall(SYS_gettid));
	while (1)
	{
		if (SYS_Role != Master_Alone_Role && SYS_Role != Master_Twins_Role)
			continue;
		if (STATE == UNCONNECT)//< 串口状态为未连接时打开串口
		{
			//< 参数一：打开串口的设备描述符
			//< 参数二：属性设置，依次为：
			//< 		O_RDWR——读写打开
			//<			O_NOCTTY——如果设备描述符指的是终端设备，则不将此设备分配作为此进程的控制终端(可以告诉Linux这个程序不会成为这个端口上的“控制终端”.如果不这样做的话,所有的输入,比如键盘上过来的Ctrl+C中止信号等等,会影响到你的进程。)
			//<			O_NDELAY——告诉Linux,这个程序并不关心DCD信号线的状态——也就是不关心端口另一端是否已经连接(非阻塞)
			if ((fd = Port_Open(Port_Name, true, O_RDWR | O_NOCTTY | O_NDELAY, Band_Rate, Data_Bits, Check_Bit, Stop_Bit)) < 0)
			{
				printf(Port_Name);
				perror("Open failed\r\n");
				WRONG_DEAL;
			}
			else
			{
				Clear_Port_Register(fd, CLEAR_IN_AND_OUT);/*清空串口发送、接收缓存区*/
				printf(Port_Name);
				printf(" Open success\r\n");				//< duan0517 注释
				for (i = 0; i < CARD_NUM; i++)
				{
					Card_Wrong_Flag[i] = false;
				}
				switch (OTHER_PORT_STATE) {					//< duan0527 根据另一串口的状态，决定当前串口的状态
				case UNCONNECT:	PORT_STATE_WRITE(WORK);	break;
				case WORK:		PORT_STATE_WRITE(BAK);	break;
				case BAK:		PORT_STATE_WRITE(WORK);	break;
				default:	break;
				}
			}				
		}

		//< 串口为备份状态时随时准备切换
		if (STATE == BAK && (OTHER_PORT_STATE == UNCONNECT || OTHER_PORT_STATE == BAK))
			PORT_STATE_WRITE(WORK);

		//< 串口为工作状态时进行读写操作
		if (STATE == WORK)
		{
			ExactDelay(SYS_BaseTime);					//< 延时系统基准周期
			for (i = 0; i < CARD_NUM; i++)
			{
				base = (NAME(MODBUS485_MASTER)*)SearchAt(((List_Base_t*)Card_List[TYPE(MODBUS485_MASTER)].ppData[0]), i);
				base->Base.Period_Count++;
				if (base->Base.Period_Count < base->Par.Card_Period) { continue; }
				else { base->Base.Period_Count = 0; }
				Wrong_Sum = 0;
				while (1)
				{
					if (MODBUS485_MASTER_RW((MODBUS485_MASTER_T*)base, fd)) { Card_Wrong_Flag[i] = false;	break; }
					else
					{
						Wrong_Sum++;
						if (Wrong_Sum >= MAX_WORK_FAIL_NUM) { Card_Wrong_Flag[i] = true; break; }						
					}						
				}
			}
			Wrong_Count = 0;
			for (i = 0; i < CARD_NUM; i++)
			{
				Wrong_Count += ((Card_Wrong_Flag[i] == true) ? 1 : 0);
			}
			if (Wrong_Count == CARD_NUM)
			{
				WRONG_DEAL;
			}
			else
			{
				FAILED_COUNT = 0;
				CANCEL_CARD_TIMEOUT_STATE;
			}
		}
	}
#undef MAX_LINK_FAIL_NUM
#undef MAX_WORK_FAIL_NUM
#undef STATE
#undef OTHER_PORT_STATE
#undef FAILED_COUNT
#undef CARD_NUM
#undef PORT_STATE_WRITE
#undef WRITE_CARD_TIMEOUT_STATE
#undef CANCEL_CARD_TIMEOUT_STATE
#undef WRONG_DEAL
}

//************************************
// Method:    	MODBUS485_MASTER_RW				MODBUS-485读写函数
// Programmer:  lww
// Time:		2019/2/27
// Returns:   	bool							true-成功；false-失败
// Parameter: 	MODBUS485_MASTER_T * base		卡件属性结构体指针
// Parameter: 	int fd							串口设备描述符
//************************************
bool MODBUS485_MASTER_RW(MODBUS485_MASTER_T* base, int fd)
{
#define PARA(name)	fd, base->Par.ModuleAddr, name, base->Par.StartAddrOf_##name, base->Sta.FunCodeNumOf_##name, base->Par.Send_MaxTime, base->Par.Recv_Respon_MaxTime

	bool flag = false;
	if (base->Sta.FunCodeNumOf_0x01 > 0)
		flag |= MODBUS485_MASTER_Funcode0x01_0x02_Work(PARA(0x01), base->Base.DIChannel);
	if (base->Sta.FunCodeNumOf_0x02 > 0)
		flag |= MODBUS485_MASTER_Funcode0x01_0x02_Work(PARA(0x02), &(base->Base.DIChannel[base->Sta.FunCodeNumOf_0x01]));
	if (base->Sta.FunCodeNumOf_0x03 > 0)
		flag |= MODBUS485_MASTER_Funcode0x03_0x04_Work(PARA(0x03), base->Base.AIChannel, base->Sta.Is_Double);
	if (base->Sta.FunCodeNumOf_0x04 > 0)
		flag |= MODBUS485_MASTER_Funcode0x03_0x04_Work(PARA(0x04), &(base->Base.AIChannel[base->Sta.FunCodeNumOf_0x03]), base->Sta.Is_Double);
	if (base->Sta.FunCodeNumOf_0x05 > 0)
		flag |= MODBUS485_MASTER_Funcode0x05_Work(PARA(0x05), base->Base.DOChannel);
	if (base->Sta.FunCodeNumOf_0x06 > 0)
		flag |= MODBUS485_MASTER_Funcode0x06_Work(PARA(0x06), base->Base.AOChannel);
	if (base->Sta.FunCodeNumOf_0x0F > 0)
		flag |= MODBUS485_MASTER_Funcode0x0F_Work(PARA(0x0F), &(base->Base.DOChannel[base->Sta.FunCodeNumOf_0x05]));
	if (base->Sta.FunCodeNumOf_0x10 > 0)
		flag |= MODBUS485_MASTER_Funcode0x10_Work(PARA(0x10), &(base->Base.AOChannel[base->Sta.FunCodeNumOf_0x06]), base->Sta.Is_Double);

	return flag;
#undef PARA
}
/*差错处理程序*/
#define WRONG_DEAL(name)	{\
	Clear_Port_Register(fd, CLEAR_IN_AND_OUT);/*清空串口发送、接收缓存区*/\
	if(name == true){\
	if (Funcode == 0x01 || Funcode == 0x02)\
		for (i = 0; i < RWNum; i++)\
			DV_Write(&(((DVChannel_t*)Ch)[i]), false, TURN_TIMEOUT);/*对该功能码对应测点做超时处理*/\
	else if (Funcode == 0x03 || Funcode == 0x04)\
		for (i = 0; i < RWNum; i++)\
			AV_Write(&(((AVChannel_t*)Ch)[i]), 0, TURN_TIMEOUT);/*对该功能码对应测点做超时处理*/\
	}\
	return false;\
}
/*报文头*/
#define MSG_HEAD	{\
	SendData[SendCount++] = ModuleAddr;						/*模件地址*/\
	SendData[SendCount++] = Funcode;						/*功能码*/\
	SendData[SendCount++] = HIGH_CHAR(StartAddr);			/*起始地址高8位*/\
	SendData[SendCount++] = LOW_CHAR(StartAddr);			/*起始地址低8位*/\
}
/*报文CRC校验*/
#define MSG_CRC_CHECK	{\
	crc = CRC_Check(SendData, SendCount);					/*CRC校验*/\
	SendData[SendCount++] = LOW_CHAR(crc);					/*CRC码低8位*/\
	SendData[SendCount++] = HIGH_CHAR(crc);					/*CRC码高8位*/\
}
/*发送请求报文*/
#define MSG_SEND	{\
	if (Port_Send(fd, SendData, SendCount, Send_MaxTime, true) < SendCount)\
	{\
		printf("Send modbus-485 request msg wrong in Funcode %d\r\n", Funcode);\
		WRONG_DEAL(false);/*duan 2019/11/8 将参数值由true更为为false。如此，超时后，主站读从站的值能够保持当前值*/\
	}\
}
/*接收响应报文*/
#define MSG_RECV	{\
	if ((RecvCount = Port_Recv(fd, RecvData, Set_RecvCount, Recv_Respon_MaxTime, true)) <= 0)\
	{\
		printf("Recv modbus-485 reponse msg wrong in Funcode %d\r\n", Funcode);/**duan0517 把这段代码先注释掉*/\
		WRONG_DEAL(false);/*duan 2019/11/8 将参数值由true更为为false。如此，超时后，主站读从站的值能够保持当前值*/\
	}\
}
/*响应报文校验*/
#define RESPOND_PCK_CHECK	{\
	crc = CRC_Check(RecvData, (RecvCount - 2));/*计算响应报文的CRC校验码*/\
	if ((LOW_CHAR(crc) != RecvData[RecvCount - 2]) || (HIGH_CHAR(crc) != RecvData[RecvCount - 1]))/*判断响应报文的CRC校验码是否正确*/\
	{\
		printf("CRC Check failed in response pack in funcode %d\r\n", Funcode);\
		WRONG_DEAL(false);\
	}\
	else if (RecvData[0] != ModuleAddr)/*判断响应报文的模件地址是否正确*/\
	{\
		printf("Module address wrong in funcode %d in module %d\r\n", Funcode, ModuleAddr);\
		WRONG_DEAL(false);\
	}\
	else if ((RecvData[1] != Funcode) && ((RecvData[1] - Funcode) == 0x80))/*判断响应报文是否包含异常信息*/\
	{\
		printf("The slave station is wrong in funcode %d, the wrongcode is %d\r\n", Funcode, RecvData[2]);\
		WRONG_DEAL(false);\
	}\
	else if(RecvCount != Set_RecvCount)\
	{\
		printf("Recv PCK length wrong in funcode %d in module %d\r\n", Funcode, ModuleAddr);\
		WRONG_DEAL(false);\
	}\
}

//************************************
// Method:    	MODBUS485_MASTER_Funcode0x01_0x02_Work		功能码1、功能码2工作函数
// Programmer:  lww
// Time:		2019/2/27
// Returns:   	bool										true-成功；false-失败
// Parameter: 	int fd										串口设备描述符
// Parameter: 	char ModuleAddr								模件地址
// Parameter: 	char Funcode								功能码
// Parameter: 	unsigned short StartAddr					起始地址
// Parameter: 	unsigned short RWNum						读写数量
// Parameter: 	int Max_WaitTime							最大超时等待时间（ms）
// Parameter: 	void * Ch									通道指针
//************************************
bool MODBUS485_MASTER_Funcode0x01_0x02_Work(int fd, unsigned char ModuleAddr, unsigned char Funcode, unsigned short StartAddr, unsigned short RWNum, int Send_MaxTime, int Recv_Respon_MaxTime, void* Ch)
{
#define REQUEST_PCK_MAXNUM	MODBUS485_FUNC0x01_0x02_REQUEST_PCK_MAXNUM			//< 请求报文最大长度
#define RESPOND_PCK_MAXNUM	MODBUS485_FUNC0x01_0x02_RESPOND_PCK_MAXNUM			//< 回复报文最大长度

	int i;
	unsigned char SendData[REQUEST_PCK_MAXNUM] = { 0 };
	unsigned char RecvData[RESPOND_PCK_MAXNUM] = { 0 };
	unsigned short SendCount = 0;
	unsigned short RecvCount = 0;
	unsigned short Set_RecvCount = 0;									//< 正确的回应报文长度
	unsigned short crc;

	MSG_HEAD;													//< 报文头
	SendData[SendCount++] = HIGH_CHAR(RWNum);					//< 读取数量高8位
	SendData[SendCount++] = LOW_CHAR(RWNum);					//< 读取数量低8位
	MSG_CRC_CHECK;												//< 报文CRC校验
	MSG_SEND;													//< 发送报文
	Set_RecvCount = 5 + RWNum / 8 + (((RWNum % 8) > 0) ? 1 : 0);//< 计算响应报文长度
	MSG_RECV;													//< 接收响应报文
	RESPOND_PCK_CHECK;											//< 响应报文校验

	for (i = 0; i < RWNum; i++) { DV_Write(&(((DVChannel_t*)Ch)[i]), ((RecvData[3 + i / 8] & (1 << (i % 8))) ? true : false), WRITE); }	//< 写入数据到数据点中
	return true;

#undef REQUEST_PCK_MAXNUM
#undef RESPOND_PCK_MAXNUM
}

//************************************
// Method:    	MODBUS485_MASTER_Funcode0x03_0x04_Work		功能码3、功能码4工作函数
// Programmer:  lww
// Time:		2019/2/27
// Returns:   	bool										true-成功；false-失败
// Parameter: 	int fd										串口设备描述符
// Parameter: 	char ModuleAddr								模件地址
// Parameter: 	char Funcode								功能码
// Parameter: 	unsigned short StartAddr					起始地址
// Parameter: 	unsigned short RWNum						读写数量
// Parameter: 	int Max_WaitTime							最大超时等待时间（ms）
// Parameter: 	void * Ch									通道指针
// Parameter: 	bool Is_Double								是否是双字MODBUS
//************************************
bool MODBUS485_MASTER_Funcode0x03_0x04_Work(int fd, unsigned char ModuleAddr, unsigned char Funcode, unsigned short StartAddr, unsigned short RWNum, int Send_MaxTime, int Recv_Respon_MaxTime, void* Ch, bool Is_Double)
{
#define REQUEST_PCK_MAXNUM	MODBUS485_FUNC0x03_0x04_REQUEST_PCK_MAXNUM	//< 请求报文最大长度
#define RESPOND_PCK_MAXNUM	MODBUS485_FUNC0x03_0x04_RESPOND_PCK_MAXNUM	//< 回复报文最大长度

	int i;
	unsigned char SendData[REQUEST_PCK_MAXNUM] = { 0 };
	unsigned char RecvData[RESPOND_PCK_MAXNUM] = { 0 };
	unsigned short SendCount = 0;
	unsigned short RecvCount = 0;
	unsigned short Set_RecvCount = 0;									//< 正确的回应报文长度
	unsigned short crc;
	
 	MSG_HEAD;																			//< 报文头
	SendData[SendCount++] = HIGH_CHAR(RWNum * ((Is_Double) ? 2 : 1));					//< 读取数量高8位
	SendData[SendCount++] = LOW_CHAR(RWNum * ((Is_Double) ? 2 : 1));					//< 读取数量低8位
	MSG_CRC_CHECK;																		//< 报文CRC校验
	MSG_SEND;																			//< 发送报文
	Set_RecvCount = 5 + 2 * RWNum * ((Is_Double) ? 2 : 1);								//< 计算响应报文长度
	MSG_RECV;																			//< 接收响应报文
	RESPOND_PCK_CHECK;																	//< 响应报文校验
	//< 写入数据到数据点中
	if (Is_Double == false)
		for (i = 0; i < RWNum; i++) { AV_Write(&(((AVChannel_t*)Ch)[i]), (float)((short)(RecvData[3 + 2 * i] << 8) + RecvData[4 + 2 * i]), WRITE); }		//< duan20191107 不支持有符号数，故修改，加上(short)强制类型转换
	else
		for (i = 0; i < RWNum; i++)
		{
			int tmp_int;
			float tmp_float;
			tmp_int = (RecvData[3 + 4 * i] << 24) + (RecvData[4 + 4 * i] << 16) + (RecvData[5 + 4 * i] << 8) + RecvData[6 + 4 * i];
			tmp_float = *((float*)(&tmp_int));
			AV_Write(&(((AVChannel_t*)Ch)[i]), tmp_float, WRITE);
		}

	return true;
	
#undef REQUEST_PCK_MAXNUM
#undef RESPOND_PCK_MAXNUM
}

//************************************
// Method:    	MODBUS485_MASTER_Funcode0x05_Work			功能码5工作函数
// Programmer:  lww
// Time:		2019/2/27
// Returns:   	bool										true-成功；false-失败
// Parameter: 	int fd										串口设备描述符
// Parameter: 	char ModuleAddr								模件地址
// Parameter: 	char Funcode								功能码
// Parameter: 	unsigned short StartAddr					起始地址
// Parameter: 	unsigned short RWNum						读写数量
// Parameter: 	int Max_WaitTime							最大超时等待时间（ms）
// Parameter: 	void * Ch									通道指针
//************************************
bool MODBUS485_MASTER_Funcode0x05_Work(int fd, unsigned char ModuleAddr, unsigned char Funcode, unsigned short StartAddr, unsigned short RWNum, int Send_MaxTime, int Recv_Respon_MaxTime, void* Ch)
{
#define REQUEST_PCK_MAXNUM	MODBUS485_FUNC0x05_REQUEST_PCK_MAXNUM			//< 请求报文最大长度
#define RESPOND_PCK_MAXNUM	MODBUS485_FUNC0x05_RESPOND_PCK_MAXNUM			//< 回复报文最大长度

	int i;
	unsigned char SendData[REQUEST_PCK_MAXNUM] = { 0 };
	unsigned char RecvData[RESPOND_PCK_MAXNUM] = { 0 };
	unsigned short SendCount = 0;
	unsigned short RecvCount = 0;
	unsigned short Set_RecvCount = 0;									//< 正确的回应报文长度
	unsigned short crc;

	MSG_HEAD;																					//< 报文头
	SendData[SendCount++] = ((((DVChannel_t*)Ch)[0].Sta_Property.CurOut_Value) ? 0xFF : 0x00);	//< 写入值高8位
	SendData[SendCount++] = 0x00;																//< 写入值低8位
	MSG_CRC_CHECK;																				//< 报文CRC校验
	MSG_SEND;																					//< 发送报文
	Set_RecvCount = SendCount;																	//< 计算响应报文长度
	MSG_RECV;																					//< 接收响应报文
	RESPOND_PCK_CHECK;																			//< 响应报文校验

	return true;

#undef REQUEST_PCK_MAXNUM
#undef RESPOND_PCK_MAXNUM
}

//************************************
// Method:    	MODBUS485_MASTER_Funcode0x06_Work			功能码6工作函数
// Programmer:  lww
// Time:		2019/2/27
// Returns:   	bool										true-成功；false-失败
// Parameter: 	int fd										串口设备描述符
// Parameter: 	char ModuleAddr								模件地址
// Parameter: 	char Funcode								功能码
// Parameter: 	unsigned short StartAddr					起始地址
// Parameter: 	unsigned short RWNum						读写数量
// Parameter: 	int Max_WaitTime							最大超时等待时间（ms）
// Parameter: 	void * Ch									通道指针
//************************************
bool MODBUS485_MASTER_Funcode0x06_Work(int fd, unsigned char ModuleAddr, unsigned char Funcode, unsigned short StartAddr, unsigned short RWNum, int Send_MaxTime, int Recv_Respon_MaxTime, void* Ch)
{
#define REQUEST_PCK_MAXNUM	MODBUS485_FUNC0x06_REQUEST_PCK_MAXNUM			//< 请求报文最大长度
#define RESPOND_PCK_MAXNUM	MODBUS485_FUNC0x06_RESPOND_PCK_MAXNUM			//< 回复报文最大长度

	int i;
	unsigned char SendData[REQUEST_PCK_MAXNUM] = { 0 };
	unsigned char RecvData[RESPOND_PCK_MAXNUM] = { 0 };
	unsigned short SendCount = 0;
	unsigned short RecvCount = 0;
	unsigned short Set_RecvCount = 0;									//< 正确的回应报文长度
	unsigned short crc;
	
	MSG_HEAD;													//< 报文头
	unsigned short tmp_short;
	tmp_short = (unsigned short)((AVChannel_t*)Ch)[0].Sta_Property.CurOut_Value;
	SendData[SendCount++] = HIGH_CHAR(tmp_short);				//< 写入值高8位
	SendData[SendCount++] = LOW_CHAR(tmp_short);				//< 写入值低8位
	MSG_CRC_CHECK;												//< 报文CRC校验
	MSG_SEND;													//< 发送报文
	Set_RecvCount = SendCount;									//< 计算响应报文长度
	MSG_RECV;													//< 接收响应报文
	RESPOND_PCK_CHECK;											//< 响应报文校验

	return true;

#undef REQUEST_PCK_MAXNUM
#undef RESPOND_PCK_MAXNUM
}

//************************************
// Method:    	MODBUS485_MASTER_Funcode0x0F_Work			功能码15工作函数
// Programmer:  lww
// Time:		2019/2/27
// Returns:   	bool										true-成功；false-失败
// Parameter: 	int fd										串口设备描述符
// Parameter: 	char ModuleAddr								模件地址
// Parameter: 	char Funcode								功能码
// Parameter: 	unsigned short StartAddr					起始地址
// Parameter: 	unsigned short RWNum						读写数量
// Parameter: 	int Max_WaitTime							最大超时等待时间（ms）
// Parameter: 	void * Ch									通道指针
//************************************
bool MODBUS485_MASTER_Funcode0x0F_Work(int fd, unsigned char ModuleAddr, unsigned char Funcode, unsigned short StartAddr, unsigned short RWNum, int Send_MaxTime, int Recv_Respon_MaxTime, void* Ch)
{
#define REQUEST_PCK_MAXNUM	MODBUS485_FUNC0x0F_REQUEST_PCK_MAXNUM			//< 请求报文最大长度
#define RESPOND_PCK_MAXNUM	MODBUS485_FUNC0x0F_RESPOND_PCK_MAXNUM			//< 回复报文最大长度

	int i;
	unsigned char SendData[REQUEST_PCK_MAXNUM] = { 0 };
	unsigned char RecvData[RESPOND_PCK_MAXNUM] = { 0 };
	unsigned short SendCount = 0;
	unsigned short RecvCount = 0;
	unsigned short Set_RecvCount = 0;									//< 正确的回应报文长度
	unsigned short crc;

	MSG_HEAD;															//< 报文头
	SendData[SendCount++] = HIGH_CHAR(RWNum);							//< 写入数量高8位
	SendData[SendCount++] = LOW_CHAR(RWNum);							//< 写入数量低8位
	SendData[SendCount++] = (unsigned char)(RWNum / 8 + (((RWNum % 8) > 0) ? 1 : 0));	//< 写入的字节数
	for (i = 0; i < RWNum; i++) { SendData[SendCount + i / 8] = (unsigned char)(SendData[SendCount + i / 8] + ((((DVChannel_t*)Ch)[i].Sta_Property.CurOut_Value) << (i % 8))); }
	SendCount += (i / 8 + 1);
	MSG_CRC_CHECK;														//< 报文CRC校验
	MSG_SEND;															//< 发送报文
	Set_RecvCount = RESPOND_PCK_MAXNUM;									//< 计算响应报文长度
	MSG_RECV;															//< 接收响应报文
	RESPOND_PCK_CHECK;													//< 响应报文校验

	return true;

#undef REQUEST_PCK_MAXNUM
#undef RESPOND_PCK_MAXNUM
}

//************************************
// Method:    	MODBUS485_MASTER_Funcode0x10_Work			功能码16工作函数
// Programmer:  lww
// Time:		2019/2/27
// Returns:   	bool										true-成功；false-失败
// Parameter: 	int fd										串口设备描述符
// Parameter: 	char ModuleAddr								模件地址
// Parameter: 	char Funcode								功能码
// Parameter: 	unsigned short StartAddr					起始地址
// Parameter: 	unsigned short RWNum						读写数量
// Parameter: 	int Max_WaitTime							最大超时等待时间（ms）
// Parameter: 	void * Ch									通道指针
// Parameter: 	bool Is_Double								是否是双字MODBUS
//************************************
bool MODBUS485_MASTER_Funcode0x10_Work(int fd, unsigned char ModuleAddr, unsigned char Funcode, unsigned short StartAddr, unsigned short RWNum, int Send_MaxTime, int Recv_Respon_MaxTime, void* Ch, bool Is_Double)
{
#define REQUEST_PCK_MAXNUM	MODBUS485_FUNC0x10_REQUEST_PCK_MAXNUM			//< 请求报文最大长度
#define RESPOND_PCK_MAXNUM	MODBUS485_FUNC0x10_RESPOND_PCK_MAXNUM			//< 回复报文最大长度

	int i;
	unsigned char SendData[REQUEST_PCK_MAXNUM] = { 0 };
	unsigned char RecvData[RESPOND_PCK_MAXNUM] = { 0 };
	unsigned short SendCount = 0;
	unsigned short RecvCount = 0;
	unsigned short Set_RecvCount = 0;										//< 正确的回应报文长度
	unsigned short crc;

	MSG_HEAD;																			//< 报文头
	SendData[SendCount++] = HIGH_CHAR(RWNum * ((Is_Double) ? 2 : 1));					//< 读取数量高8位
	SendData[SendCount++] = LOW_CHAR(RWNum * ((Is_Double) ? 2 : 1));					//< 读取数量低8位
	SendData[SendCount++] = (unsigned char)(2 * RWNum * ((Is_Double) ? 2 : 1));			//< 写入的字节数
	if (Is_Double == false)
		for (i = 0; i < RWNum; i++)
		{
			short tmp_short;
			tmp_short = (short)((AVChannel_t*)Ch)[i].Sta_Property.CurOut_Value;
			SendData[SendCount + 2 * i] = HIGH_CHAR(tmp_short);
			SendData[SendCount + 2 * i + 1] = LOW_CHAR(tmp_short);
		}
	else
		for (i = 0; i < RWNum; i++)
		{
			int tmp_int;
			tmp_int = *((int*)(&((AVChannel_t*)Ch)[i].Sta_Property.CurOut_Value));
			SendData[SendCount + 4 * i] = (unsigned char)((tmp_int >> 24) & 0xFF);
			SendData[SendCount + 4 * i + 1] = (unsigned char)((tmp_int >> 16) & 0xFF);
			SendData[SendCount + 4 * i + 2] = (unsigned char)((tmp_int >> 8) & 0xFF);
			SendData[SendCount + 4 * i + 3] = (unsigned char)(tmp_int & 0xFF);
		}
	SendCount += (int)(2 * RWNum * ((Is_Double) ? 2 : 1));
	MSG_CRC_CHECK;												//< 报文CRC校验
	MSG_SEND;													//< 发送报文
	Set_RecvCount = RESPOND_PCK_MAXNUM;							//< 计算响应报文长度
	MSG_RECV;													//< 接收响应报文
	RESPOND_PCK_CHECK;											//< 响应报文校验

	return true;

#undef REQUEST_PCK_MAXNUM
#undef RESPOND_PCK_MAXNUM
}
#undef WRONG_DEAL
#undef MSG_HEAD
#undef MSG_CRC_CHECK
#undef MSG_SEND
#undef MSG_RECV
#undef RESPOND_PCK_CHECK

//************************************
// Method:    	CHANGE_CARD_LIST_PAR		修改该类型卡件属性
// Programmer:  lww
// Time:		2019/4/4
// Returns:   	int							读取字节长度计数值
// Parameter: 	Card_Base_t* arg			指定卡件属性结构体的指针
// Parameter: 	void** Data					存放数据包当前指针位置的地址
//************************************
int CHANGE_CARD_LIST_PAR(MODBUS485_MASTER)(Card_Base_t* arg, void** Data)
{
	int _iLen = 0;
	MEMREAD((*CLIST_PAR(MODBUS485_MASTER)), Data[0]);
	return _iLen;
}


//************************************
// Method:    	CHANGE_CARD_PAR				在线修改卡件参数函数
// Programmer:  lww
// Time:		2018/11/16
// Returns:   	int							读取字节长度计数值
// Parameter: 	Card_Base_t* arg			指定卡件属性结构体的指针
// Parameter: 	void** Data					存放数据包当前指针位置的地址
//************************************
int CHANGE_CARD_PAR(MODBUS485_MASTER)(Card_Base_t* arg, void** Data)
{
	int _iLen = 0;
	MEMREAD(((NAME(MODBUS485_MASTER)*)arg)->Par, Data[0]);
	return _iLen;
}


//************************************
// Method:    	INIT_STAPAR					初始化卡件不可调参数结构体
// Programmer:  lww
// Time:		2018/11/16
// Returns:   	int							读取字节长度计数值
// Parameter: 	Card_Base_t* arg			指定卡件属性结构体的指针
// Parameter: 	void** Data					存放数据包当前指针位置的地址
//************************************
int INIT_CARD_STA(MODBUS485_MASTER)(Card_Base_t* arg, void** Data)
{
	int _iLen = 0;
	MEMREAD(((NAME(MODBUS485_MASTER)*)arg)->Sta, Data[0]);
	return _iLen;
}
